package net.guerlab.sdk.anubis.config;

import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.fasterxml.jackson.databind.ObjectMapper;

import net.guerlab.sdk.anubis.AnubisConstants;
import net.guerlab.sdk.anubis.accesstoken.AccessTokenManager;
import net.guerlab.sdk.anubis.accesstoken.AccessTokenStorage;
import net.guerlab.sdk.anubis.client.AnubisClient;
import net.guerlab.sdk.anubis.client.impl.DefaultAnubisClient;
import net.guerlab.sdk.anubis.helper.NotifyHelper;
import okhttp3.OkHttpClient;

/**
 * 蜂鸟自动配置
 *
 * @author guer
 *
 */
@Configuration
@EnableConfigurationProperties(AnubisConfig.class)
public class AnubisAutoConfiguration {

    private static final Logger LOGGER = LoggerFactory.getLogger(AnubisAutoConfiguration.class);

    @Autowired
    private AnubisConfig config;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired(required = false)
    private OkHttpClient okHttpClient;

    /**
     * 创建默认蜂鸟请求客户端
     *
     * @return 蜂鸟请求客户端
     */
    @Bean
    public AnubisClient anubisClient() {
        String appId = config.getAppId();
        String secretKey = config.getSecretKey();
        String host = config.isDev() ? AnubisConstants.HOST_DEV : AnubisConstants.HOST_PRODUCED;

        return new DefaultAnubisClient(appId, secretKey, host, getOkHttpClient(), objectMapper);
    }

    /**
     * 创建通知助手
     *
     * @return 通知助手
     */
    @Bean
    public NotifyHelper anubisNotifyHelper() {
        NotifyHelper notifyHelper = new NotifyHelper();
        notifyHelper.setObjectMapper(objectMapper);

        return notifyHelper;
    }

    /**
     * 设置AccessToken储存接口
     *
     * @param accessTokenStorage
     *            AccessToken储存接口
     */
    @Autowired(required = false)
    public void setAccessTokenStorage(
            AccessTokenStorage accessTokenStorage) {
        if (accessTokenStorage != null) {
            AccessTokenManager.instance().setStorage(accessTokenStorage);
        }
    }

    private OkHttpClient getOkHttpClient() {
        if (okHttpClient != null) {
            return okHttpClient;
        }

        return createHttpClient();
    }

    /**
     * 创建http请求客户端
     *
     * @return http请求客户端
     */
    public static OkHttpClient createHttpClient() {
        return new OkHttpClient.Builder().connectTimeout(10, TimeUnit.SECONDS).readTimeout(10, TimeUnit.SECONDS)
                .writeTimeout(10, TimeUnit.SECONDS).sslSocketFactory(createSSLSocketFactory(), new TrustAllManager())
                .hostnameVerifier((
                        hostname,
                        session) -> true)
                .build();
    }

    private static SSLSocketFactory createSSLSocketFactory() {
        SSLSocketFactory sSLSocketFactory = null;

        try {
            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(null, new TrustManager[] {
                    new TrustAllManager()
            }, new SecureRandom());
            sSLSocketFactory = sc.getSocketFactory();
        } catch (Exception e) {
            LOGGER.debug(e.getMessage(), e);
        }

        return sSLSocketFactory;
    }

    private static class TrustAllManager implements X509TrustManager {

        @Override
        public void checkClientTrusted(
                X509Certificate[] chain,
                String authType) throws CertificateException {
            /**
             * not todo some thing
             */
        }

        @Override
        public void checkServerTrusted(
                X509Certificate[] chain,
                String authType) throws CertificateException {
            /**
             * not todo some thing
             */
        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[] {};
        }
    }

}
